home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
SPACE 1
/
SPACE - Library 1 - Volume 1.iso
/
program
/
441
/
gemfxm12
/
minicolr.c
< prev
next >
Wrap
C/C++ Source or Header
|
1990-11-23
|
37KB
|
859 lines
/**************************************************************************
*
* mini_pallete - A little bitty control-panel-like color pallete acc.
*
* Public Domain example program by Ian Lepore.
*
* This is distributed as an example of how to write an accessory using
* my AESFAST public domain GEM bindings. This example uses a few of
* the nifty utilities from AESFAST, but it's pretty much straightforward
* window-handling code.
*
* I built this beast because I have some graphics programs (Mandelbrot
* fractal generators, a spyrograph program, etc), in which one would
* naturally want to change the screen colors on the fly, but the %^$%#*&
* system control panel covers the whole screen in low rez. This acc
* gives a nice itty-bitty moveable window with all the necessary color
* controls in it.
*
* This acc does not behave like the system control panel, in that it
* will not reset the colors the application has set when you call it up.
* On the other hand, the color changes you do with this accessory will
* not be saved if you use 'Save Desktop'. (Hint: You would need to code
* the shel_read() and shel_write() AES functions to make that work.
* Actually doing it is left as an excerise for the reader <grin>).
*
* Also, the order of the colored boxes on the screen corresponds to the
* TOS order of colors, not the VDI order. (EG: The foreground and
* background colors are the first and last boxes, not the first two).
*
* This code is pretty heavily commented. Please excuse me if some of
* the comments seem obvious, but I figure the audience for this will
* include both beginning C programmers, and old-timers who just need to
* see how my bindings work as opposed to other bindings.
*
*************************************************************************/
#include <gemfast.h>
#include <osbind.h>
#ifndef TRUE
#define TRUE 1
#define FALSE 0
#endif
#define Getcolor(a) ((int)(Setcolor((a), -1)))
#define graf_mkstate graq_mstate /* use Line-A mouse state call */
/**************************************************************************
*
* global vars (gee, there's not many of these for a change...)
*
*************************************************************************/
struct rgb_settings {
char red, grn, blu, filler;
} cur_setting;
int coloridx = 0; /* default color index is # 0 */
#define WI_KIND (MOVER|CLOSER|NAME)
#define NO_WINDOW -1
extern int gl_apid; /* defined in bindings library */
int menu_id ; /* our menu id */
int wi_handle; /* window handle */
GRECT treerect; /* object tree (in window) rect */
char menu_title[] = " Mini Pallete ";
char wind_title[] = " Mini Pallete ";
/**************************************************************************
*
* palttree - The color pallete dialog tree.
*
* This is NOT the output from a resource editor (it was a long time ago,
* but it's been pretty much re-done by hand).
*
* About extended object types...
*
* The ob_type field is a word, but the AES only uses the lower byte of
* it. It has become a sort of standard technique for programs to use
* the upper byte for their own evil purposes. (Really, the object
* structure should have had an 'ob_apspec' longword in it for the
* application's use). Anyway, there is some discussion under the
* 'find_boxchar' routine below on accessing arrays of objects in a tree
* without being sure where the objects are in the tree array. The
* methods discussed below work fine for boxchar objects; the extended
* object type can be used for other types of objects.
*
* For example, suppose you have 10 strings in a dialog box. You want to
* set the ob_spec pointers at runtime to correspond to the elements in
* an array of strings you've defined in your program. You can code a
* lot of C statements using the hard-coded object names, but what if you
* have 50 strings instead of 10? More to the point, what if some hacker
* edits the .RSC file and changes the order of the objects? Bombs, that's
* what. So, you can (with most resource editors) set the extended
* object type for the strings to the numbers 1-10, then at runtime you
* can scan the tree looking for an object with an extended type of 1,
* then set the first string pointer, then scan for 2, and so on. Now,
* no matter where those strings get moved to in the tree structure, they
* will be found at runtime and pointers will be assigned properly.
*
* Now that I've described this nifty string-thing, I should mention that
* this program doesn't use that techique, as it contains no strings in
* the dialog.
*
* This program uses the extended object type to hold the TOS color index
* value that corresponds to the colored box which is the object. This
* is due to the screwy way the ST maps TOS colors to VDI colors. If you
* compare the VDI/object color number in the ob_spec field to the extended
* object type value, you'll see the translation table that maps TOS colors
* to GEM colors. For the ob_type values below which are not described
* by name, the format is 0xcc14, where 'cc' is the TOS color number, and
* '14' is a box type object.
*
* The ob_spec field for box-like objects maps out as follows:
* 0xaabbcdef
* |||||||+-- inside fill color
* ||||||+--- fill pattern and opaque/transparent flag
* |||||+---- text color
* ||||+----- border color
* ||++------ border thickness (neg = outside width, pos = inside width)
* ++-------- ASCII character for boxchar objects, zero for other types
*
* The two objects flagged as HIDETREE are no longer used, and I don't
* want to rebuild the whole tree to remove them (and I've lost the
* .RSC file that this source comes from).
*************************************************************************/
OBJECT palttree[] = {
/* type flags state ob_spec x y w h */
-1, 1, 35, G_BOX, NONE, 0, 0x00000000L, 0x0000, 0x0000, 0x0212, 0x0506,
2, -1, -1, G_BOXCHAR, HIDETREE, 0, 0x05FF1100L, 0x0000, 0x0000, 0x0000, 0x0000,
3, -1, -1, G_BOX, HIDETREE, 0, 0x00FF1121L, 0x0000, 0x0000, 0x0000, 0x0000,
7, 4, 6, G_IBOX, NONE, 0, 0x00001101L, 0x0100, 0x0100, 0x0401, 0x0703,
5, -1, -1, G_BOXCHAR, NONE, 0, 0x52001100L, 0x0200, 0x0100, 0x0001, 0x0001,
6, -1, -1, G_BOXCHAR, NONE, 0, 0x47001100L, 0x0200, 0x0401, 0x0001, 0x0001,
3, -1, -1, G_BOXCHAR, NONE, 0, 0x42001100L, 0x0200, 0x0702, 0x0001, 0x0001,
35, 8, 26, G_IBOX, NONE, 0, 0x00001100L, 0x0501, 0x0200, 0x0210, 0x0603,
17, 9, 16, G_IBOX, NONE, 0, 0x00001100L, 0x0100, 0x0000, 0x0010, 0x0001,
10, -1, -1, G_BOXCHAR, NONE, 0, 0x30FF1100L, 0, 0, 2, 1,
11, -1, -1, G_BOXCHAR, NONE, 0, 0x31FF1100L, 2, 0, 2, 1,
12, -1, -1, G_BOXCHAR, NONE, 0, 0x32FF1100L, 4, 0, 2, 1,
13, -1, -1, G_BOXCHAR, NONE, 0, 0x33FF1100L, 6, 0, 2, 1,
14, -1, -1, G_BOXCHAR, NONE, 0, 0x34FF1100L, 8, 0, 2, 1,
15, -1, -1, G_BOXCHAR, NONE, 0, 0x35FF1100L, 10, 0, 2, 1,
16, -1, -1, G_BOXCHAR, NONE, 0, 0x36FF1100L, 12, 0, 2, 1,
8, -1, -1, G_BOXCHAR, NONE, 0, 0x37FF1100L, 14, 0, 2, 1,
26, 18, 25, G_IBOX, NONE, 0, 0x00001100L, 0x0100, 0x0301, 0x0010, 0x0001,
19, -1, -1, G_BOXCHAR, NONE, 0, 0x30FF1100L, 0, 0, 2, 1,
20, -1, -1, G_BOXCHAR, NONE, 0, 0x31FF1100L, 2, 0, 2, 1,
21, -1, -1, G_BOXCHAR, NONE, 0, 0x32FF1100L, 4, 0, 2, 1,
22, -1, -1, G_BOXCHAR, NONE, 0, 0x33FF1100L, 6, 0, 2, 1,
23, -1, -1, G_BOXCHAR, NONE, 0, 0x34FF1100L, 8, 0, 2, 1,
24, -1, -1, G_BOXCHAR, NONE, 0, 0x35FF1100L, 10, 0, 2, 1,
25, -1, -1, G_BOXCHAR, NONE, 0, 0x36FF1100L, 12, 0, 2, 1,
17, -1, -1, G_BOXCHAR, NONE, 0, 0x37FF1100L, 14, 0, 2, 1,
7, 27, 34, G_IBOX, NONE, 0, 0x00001100L, 0x0100, 0x0602, 0x0010, 0x0001,
28, -1, -1, G_BOXCHAR, NONE, 0, 0x30FF1100L, 0, 0, 2, 1,
29, -1, -1, G_BOXCHAR, NONE, 0, 0x31FF1100L, 2, 0, 2, 1,
30, -1, -1, G_BOXCHAR, NONE, 0, 0x32FF1100L, 4, 0, 2, 1,
31, -1, -1, G_BOXCHAR, NONE, 0, 0x33FF1100L, 6, 0, 2, 1,
32, -1, -1, G_BOXCHAR, NONE, 0, 0x34FF1100L, 8, 0, 2, 1,
33, -1, -1, G_BOXCHAR, NONE, 0, 0x35FF1100L, 10, 0, 2, 1,
34, -1, -1, G_BOXCHAR, NONE, 0, 0x36FF1100L, 12, 0, 2, 1,
26, -1, -1, G_BOXCHAR, NONE, 0, 0x37FF1100L, 14, 0, 2, 1,
0, 36, 51, G_IBOX, NONE, 0, 0x00001100L, 0x0000, 0x0104, 0x0212, 0x0302,
37, -1, -1, 0x0014, NONE, 0, 0x00011170L, 512, 512, 2, 1,
38, -1, -1, 0x0814, NONE, 0, 0x00000179L, 512, 769, 2, 1,
39, -1, -1, 0x0114, NONE, 0, 0x00001172L, 1026, 512, 2, 1,
40, -1, -1, 0x0214, NONE, 0, 0x00002173L, 1540, 512, 2, 1,
41, -1, -1, 0x0314, NONE, 0, 0x00003176L, 7, 512, 2, 1,
42, -1, -1, 0x0414, NONE, 0, 0x00000174L, 521, 512, 2, 1,
43, -1, -1, 0x0514, NONE, 0, 0x00001177L, 1035, 512, 2, 1,
44, -1, -1, 0x0614, NONE, 0, 0x00002175L, 1549, 512, 2, 1,
45, -1, -1, 0x0A14, NONE, 0, 0x0000217BL, 1540, 769, 2, 1,
46, -1, -1, 0x0B14, NONE, 0, 0x0000317EL, 7, 769, 2, 1,
47, -1, -1, 0x0C14, NONE, 0, 0x0000017CL, 521, 769, 2, 1,
48, -1, -1, 0x0D14, NONE, 0, 0x0000117FL, 1035, 769, 2, 1,
49, -1, -1, 0x0E14, NONE, 0, 0x0000217DL, 1549, 769, 2, 1,
50, -1, -1, 0x0714, NONE, 0, 0x00003178L, 16, 512, 2, 1,
51, -1, -1, 0x0914, NONE, 0, 0x0000117AL, 1026, 769, 2, 1,
35, -1, -1, 0x0F14, LASTOB, 0, 0x00003171L, 16, 769, 2, 1
}; /* END of palttree[] */
/* resource set indicies (names) for objects in palttree */
#define PALTTREE 0 /* root */
#define PALTPNUM 7 /* Parent box for all the intensity parents */
#define PALTPRED 8 /* Parent box for the RED intensity numbers */
#define PALTPGRN 17 /* Parent box for the GRN intensity numbers */
#define PALTPBLU 26 /* Parent box for the BLU intensity numbers */
#define PALTPCOL 35 /* Parent box for the color-selection boxes */
/**************************************************************************
*
* find_boxchar - Return the object index of a child boxchar with a given
* letter in its box, or -1 if no matching object can be found.
*
* Say what? Well, this routine cruises through all the children of a
* given parent object, and for every boxchar type object found the char
* in the box is compared to the char passed to this routine. On the
* first match found, the object index of the matching object is returned.
* (Note that the object type is masked with 0x00FF to strip out any
* extended object type info, so that the object type compare will work).
*
* Why do this, you wonder? Well, boxchar objects make great radio
* buttons, especially for things like selecting a device, or in this
* case, a color intensity from 0-7. In the case of device selection,
* you need to have buttons for A-P, but on most systems, there won't
* be this many devices, and you'll need to set some of the buttons
* (boxchars) to DISABLED. Since you'll be doing this at runtime, you
* need a way to find the corresponding button for each device. It is
* AN ABSOLUTE NO-NO to hard-code object indicies (names) or treat the
* objects as an array, because as soon as you do some user will come
* along with a resouce editor & re-sort your objects. Then the user will
* complain when s/he clicks on the drive A button, and drive B gets
* formatted instead.
*
*************************************************************************/
int
find_boxchar(tree, parent, boxchar)
register OBJECT *tree;
register int parent;
register char boxchar;
{
register int kid;
kid = tree[parent].ob_head;
while ( (kid != parent) && (kid >= R_TREE) ) {
if ((0x00FF & tree[kid].ob_type) == G_BOXCHAR) {
if (boxchar == (char)(tree[kid].ob_spec >> 24)) {
return(kid);
}
}
kid = tree[kid].ob_next;
}
return(-1);
}
/**************************************************************************
*
* objxrb_which - Extended radio-button-finder... Find the object within
* a given parent which has an object state matching the parm passed to
* this routine. (The normal rb-finder looks only for SELECTED, this
* routine can find CROSSED, etc).
*
* This routine returns the object index of the first object that matches
* the requested state, or -1 if no objects match. Note that the object
* does not have to be a radio button, in fact that isn't even checked.
*
* The check is done via a bit-wise AND, so it *is not* possible to find
* an object only if it is both SELECTED and CHECKED (or whatever); in that
* case, the routine will find the first object that's in *either* state.
*************************************************************************/
int
objxrb_which(tree, parent, rbstate)
register OBJECT *tree;
register int parent;
register char rbstate;
{
register int kid;
kid = tree[parent].ob_head;
while ( (kid != parent) && (kid >= R_TREE) ) {
if (tree[kid].ob_state & rbstate) {
return(kid);
}
kid = tree[kid].ob_next;
}
return(-1);
}
/**************************************************************************
*
* rgb2color - convert cur_settings structure to a TOS color value.
* This routine combines the separate ASCII RGB values into a single
* integer RGB value in TOS format. That is, if the cur_settings struct
* contains '2', '6', and '3', this routine will return 0x0263.
*
*************************************************************************/
int
rgb2color()
{
return ( ((cur_setting.red & 0x000F) << 8) |
((cur_setting.grn & 0x000F) << 4) |
(cur_setting.blu & 0x000F) );
}
/**************************************************************************
*
* color2rgb - convert a TOS color to characters in cur_settings.
* This routine separates an integer TOS-format RGB value into 3 ASCII
* characters in cur_settings. If the TOS color is 0x0746, the structure
* will contain '7', '4', and '6'.
*
*************************************************************************/
void
color2rgb(color)
register int color;
{
cur_setting.red = '0' + ( 0x000F & (color >> 8) );
cur_setting.grn = '0' + ( 0x000F & (color >> 4) );
cur_setting.blu = '0' + ( 0x000F & color );
}
/**************************************************************************
*
* new_color - Change the current selected color box on the screen (like
* a radio button), and set the new intensity settings (numbered boxes)
* to match the new active color box.
*
* To show which color box is current, we set the ob_state to CROSSED
* instead of SELECTED. SELECTED will invert the color of the object,
* which sorta defeats our purpose. We don't have as much room on the
* screen as the regular control panel, so we can't just make the box
* a little bigger like it does.
*
* If 'drawflag' is TRUE, the screen is updated with the state changes
* (this is the normal state of affairs). If the flag is FALSE, the
* object states are set, but no screen work is done (this is for
* initializing the dialog before it is displayed).
*************************************************************************/
void
new_color(newobject, drawflag)
register int newobject, drawflag;
{
register OBJECT *ptree;
register int wrkobject;
register int curobject;
int dmy;
ptree = palttree; /* quick register tree pointer */
/*
* figure out which is the currently-selected color box object.
* if the current object is the same as the new object, the user is
* leaning on the mouse button; to avoid nasty object flashing on
* the screen in this case, just return.
*/
curobject = objxrb_which(ptree, PALTPCOL, CROSSED);
if (curobject == newobject) {
return;
}
/*
* de-select the numbered radio buttons that show the intensity
* settings for the current color. the 'if (-1 != ...)' logic prevents
* us from croaking the first time thru, since no buttons will be selected.
*/
if (-1 != (wrkobject = objrb_which(ptree, PALTPRED)))
objst_change(ptree, wrkobject, ~SELECTED, drawflag);
if (-1 != (wrkobject = objrb_which(ptree, PALTPGRN)))
objst_change(ptree, wrkobject, ~SELECTED, drawflag);
if (-1 != (wrkobject = objrb_which(ptree, PALTPBLU)))
objst_change(ptree, wrkobject, ~SELECTED, drawflag);
/*
* de-select the current color box, select the new color box.
* again the '-1' check is for the first time thru case.
*/
if (-1 != curobject)
objst_change(ptree, curobject, ~CROSSED, drawflag);
objst_change(ptree, newobject, CROSSED, drawflag);
/*
* change our picture of what's current. the TOS color index is encoded
* as the 'extended object type' of the color-box objects (see discussion
* on this above, where palttree is defined). the 'color2rgb' call will
* fill in the 'cur_settings' structure to represent the current intensity
* of the color just selected.
*/
coloridx = 0x000F & (ptree[newobject].ob_type >> 8);
color2rgb( Getcolor(coloridx) );
/*
* select the appropriate numbered boxes to represent the color intensity
* settings for the newly-selected color. the 'cur_settings' array holds
* the ASCII representation of the RGB instensities. this is done so that
* we can find the corresponding radio buttons (which are BOXCHAR objects)
* via the find_boxchar() function.
*/
wrkobject = find_boxchar(ptree, PALTPRED, cur_setting.red);
objst_change(ptree, wrkobject, SELECTED, drawflag);
wrkobject = find_boxchar(ptree, PALTPGRN, cur_setting.grn);
objst_change(ptree, wrkobject, SELECTED, drawflag);
wrkobject = find_boxchar(ptree, PALTPBLU, cur_setting.blu);
objst_change(ptree, wrkobject, SELECTED, drawflag);
/* all done */
}
/**************************************************************************
*
* new_settings - Process a click in a numbered box of the dialog, and
* change the color intensity in the TOS color pallete correspondingly.
*
*************************************************************************/
void
new_settings(newobject)
{
char boxchar;
int curparent,
curobject;
/*
* figure out what's being changed. the 'curparent' value will tell us
* whether it's the R, G, or B value. the 'curobject' is used to detect
* whether the user is leaning on the mouse (curobject == newobject);
* in this case we exit without taking any action, to avoid nasty graphic
* flashing on the screen.
*
*/
curparent = obj_parent(palttree, newobject);
curobject = objrb_which(palttree, curparent);
if (curobject == newobject) {
return;
}
/*
* the displayed intensity buttons are G_BOXCHAR objects, with the chars
* ranging from '0' - '7' for each color. we pluck the displayed char
* out of the ob_spec value in the tree (ob_spec for boxchars looks like
* 0xCCnnnnnn), and we plug the char right into the 'cur_settings' array,
* still in its ASCII form.
*/
boxchar = (char)(palttree[newobject].ob_spec >> 24);
switch (curparent) {
case PALTPRED:
cur_setting.red = boxchar;
break;
case PALTPGRN:
cur_setting.grn = boxchar;
break;
case PALTPBLU:
cur_setting.blu = boxchar;
break;
}
/*
* now that the 'cur_settings' array contains the new intensity setting,
* call 'rgb2color' to convert the ASCII values to a single binary TOS
* color value, then call the TOS 'Setcolor' function to make the change.
*/
Setcolor( coloridx, rgb2color() );
/*
* de-select the old intensity setting, select the new one...
*/
objst_change(palttree, curobject, ~SELECTED, TRUE);
objst_change(palttree, newobject, SELECTED, TRUE);
/* all done */
}
/**************************************************************************
*
* prg_init - Mundane program init stuff.
* The only item of note here is a call to 'rsc_treefix'. This is a
* routine from the AESFAST library that will do an rsrc_obfix() call for
* each object in a tree. It's used only for resource trees buried in
* source code, if the resource file is loaded, the rsrc_load() call
* handles the object x/y/w/h fixup internally.
*
* Oh yeah -- I discovered an interesting problem coding this: If the
* 'menu_register' call is not the first AES call following the appl_init
* the accessory sometimes doesn't show up on the DESK menu until
* after you've run some other GEM program. This is consistant with the
* rules of AES multitasking: your program can be swapped out on ANY
* AES call, not just when you do an evnt_???? call. It just isn't
* mentioned in any of the docs I have.
*************************************************************************/
prg_init()
{
appl_init();
menu_id = menu_register(gl_apid, menu_title);
rsc_treefix(palttree);
form_center(palttree, &treerect.g_x, &treerect.g_y,
&treerect.g_w, &treerect.g_h);
new_color(0, FALSE);
wi_handle = NO_WINDOW;
}
/**************************************************************************
*
* open_window
* Create and open the window, if it's not open already.
*
* If the window is already open, it may be hidden from the user by an
* overlapping window, and the only way to get us back may be to
* click on us again in the DESK menu. In this case, we just ask
* the AES to bring our window back to the top.
*
* Before opening the window, we calculate its size and location (total
* size, including its borders & controls) based upon the current size
* and location of the pallete object tree. The first time the window
* opens, this will be the center of the screen, because we do a
* form_center on the pallete tree. For subsequent calls, we show up
* wherever we were last on the screen.
*
* We also set the window title bar here, before opening the window.
*************************************************************************/
open_window()
{
GRECT windrect;
if (wi_handle == NO_WINDOW) {
wind_calc(WC_BORDER, WI_KIND, treerect,
&windrect.g_x, &windrect.g_y,
&windrect.g_w, &windrect.g_h);
wi_handle = wind_create(WI_KIND, windrect);
wind_set(wi_handle, WF_NAME, wind_title, 0L);
wind_open(wi_handle, windrect);
}
else {
wind_set(wi_handle, WF_TOP, 0L, 0L);
}
}
/**************************************************************************
*
* close_window
* Close and delete the window, if it's open.
*************************************************************************/
close_window()
{
if (wi_handle != NO_WINDOW) {
wind_close(wi_handle);
wind_delete(wi_handle);
wi_handle = NO_WINDOW;
}
}
/**************************************************************************
*
* do_redraw - Process redraw list.
* Ok, let's see if I can explain this better than the DRI books do...
*
* After somebody has munged up the screen (say with a dialog box), they
* send a redraw request to the whole world. The redraw request comes
* from one of two sources: 1) Somebody does a form_dial(FMD_FINISH...)
* call, or 2) Somebody does a wind_close() call. (Ummm, ok, so there's
* other sources, now that I think of it, like windows being moved or
* sized). Anyway, when AES sends out a redraw request, it sends it to
* everybody who owns a window, and what it sends is the full x/y/w/h
* values of the area of the screen to restore.
*
* The area to be restored may or may not overlap any of the windows you
* have open on the screen. The AES can provide you with a list of the
* visible rectangles that comprise your window(s). (Remember that not
* all of a window you have open may be visible). So, to process a
* redraw, you have to ask AES for each of the visible rectangles, and
* for each one returned, see if it overlaps the screen area to be redrawn.
*
* There is a library routine in AESFAST called 'rc_intersect' that will
* compute the intersecting portion of 2 rectangular screen areas. If
* the rectangles don't overlap at all, it will return FALSE. Thus, we
* have a loop in which we ask the AES for each rectangle, and we check
* it against the redraw rectangle, and if there is some overlap, we call
* the routine which actually draws the window contents, passing that
* routine the boundries of the intersecting rectangle. The looping
* continues until the AES returns us a rectangle from the list that has
* zero height and width.
*
*************************************************************************/
do_redraw(updtrect)
GRECT updtrect; /* the full area that needs updating */
{
GRECT listrect; /* one of our visible areas */
wind_get(wi_handle, WF_FIRSTXYWH,
&listrect.g_x, &listrect.g_y,
&listrect.g_w, &listrect.g_h);
while ( listrect.g_w && listrect.g_h ) {
if ( rc_intersect(&updtrect, &listrect) ) {
draw_window(listrect);
}
wind_get(wi_handle, WF_NEXTXYWH,
&listrect.g_x, &listrect.g_y,
&listrect.g_w, &listrect.g_h);
}
}
/**************************************************************************
*
* draw_window - Draw the contents of the window, with clipping.
* In this case, we just do an objc_draw call on our tree, passing the
* clipping rectangle we receive along to the objc_draw.
*
*************************************************************************/
draw_window(cliprect)
GRECT cliprect;
{
objc_draw(palttree, R_TREE, MAX_DEPTH, cliprect);
}
/**************************************************************************
*
* just for grins dept: This is what a draw_window() routine might
* look like if the window was not based upon an object tree. I'm
* assuming a really stupid window which has a circle and some blit-based
* graphics in it.
*
*************************************************************************/
#if 0 /* don't really compile this code... */
draw_vwindow(cliprect)
GRECT cliprect;
{
long dmyfdb = 0L;
VRECT vdiclip;
struct {
VRECT blit1rect;
VRECT blit2rect;
} blitarea;
/*
* convert the GRECT-type clipping rectangle (x/y/w/h) to a VRECT-type
* rectangle (x1,y1,x2,y2). set the VDI clipping area, and call the
* VDI circle function.
*/
rc_gtov(&cliprect, &vdiclip);
vs_clip(vdi_handle, &vdiclip, TRUE);
v_circle(vdi_handle, x, y, r);
/*
* for the blit, I'm assuming the blit buffer is a 32k screen image, and
* you just want to blit the corresponding area back onto the screen. the
* MFDB structure describing the blit buffer has already been filled out
* before this routine is ever called <grin>. (Obscure Fact Dept: for
* blitting to the screen, a full MFDB is not needed...one only needs
* a longword of zeroes, which is a key telling VDI to use the screen as
* the destination.)
*
* the blit routine needs a VRECT describing the source and another
* describing the destination, and the docs always describe this as a
* 'pxy array', so everybody defines pxy[8] and tediously loads all the
* array elements with x/y values. structures in C place all the elements
* contiguously, so the 'blitarea' structure defined above is pretty much
* equivelent to using a pxy array, except the code is now *much* more
* readable.
*/
rc_gtov(&cliprect, &blitarea.blit1rect);
rc_gtov(&cliprect, &blitarea.blit2rect);
vro_cpyfm(vdi_handle, S_ONLY, &blitarea, &sourcefdb, &dmyfdb);
}
#endif
/**************************************************************************
*
* do_msg - Handle a message returned by evnt_multi().
* This is pretty standard message handling for an accessory. One item of
* interest I discovered when building this is that you should *not*
* attempt to close any open windows when you get an AC_CLOSED message.
* This message apparently tells you that your windows have already been
* closed and deleted, and you should just mark your window handle(s) as
* no longer valid.
*
* The only piece of weirdness here is the WM_MOVED case. The window
* provides a frame for our object tree, so when it gets moved, we have
* to update the ob_x and ob_y values in the pallete tree to match (so
* that objc_draw commands will draw inside the window's work area).
* The values in msgbuf reflect the new x/y/w/h of the window's total
* size (borders and controls included). We have the option of changing
* these values (like snapping to a character grid or whatever) or even
* of ignoring them, but in this instance we don't care about any of that
* so we just tell AES to use the values directly. After doing the
* wind_set call to set the new location of the window, we call wind_get
* to find out the new x/y/w/h of the work area of the window, so that
* we can reposition the object tree. We don't have to redraw the
* window contents during WM_MOVED processing, because the AES will blit
* the window contents for us if it can. If not all of the window can
* be blitted, the AES will send redraw messages to us, and we'll get
* them on the next iteration of the evnt_multi loop.
*************************************************************************/
do_msg(msgbuf)
register int msgbuf[];
{
switch (msgbuf[0]) {
case AC_OPEN:
if (msgbuf[4] == menu_id)
open_window();
break;
case AC_CLOSE:
wi_handle = NO_WINDOW;
break;
case WM_REDRAW:
if (msgbuf[3] == wi_handle)
do_redraw(msgbuf[4], msgbuf[5],
msgbuf[6], msgbuf[7]);
break;
case WM_NEWTOP:
case WM_TOPPED:
if (msgbuf[3] == wi_handle)
wind_set(wi_handle, WF_TOP, 0L, 0L);
break;
case WM_CLOSED:
close_window();
break;
case WM_MOVED:
if(msgbuf[3] == wi_handle) {
wind_set(wi_handle, WF_CURRXYWH,
msgbuf[4], msgbuf[5],
msgbuf[6], msgbuf[7]);
wind_get(wi_handle, WF_WORKXYWH,
&treerect.g_x, &treerect.g_y,
&treerect.g_w, &treerect.g_h);
palttree->ob_x = treerect.g_x;
palttree->ob_y = treerect.g_y;
}
break;
} /* END switch (msgbuf[0]) */
}
/**************************************************************************
*
* do_btn - Handle a button click within our window.
* Do a graf_mkstate() call to get the most-current location of the
* mouse. Call objc_find() to see if the mouse is located over an object
* in our tree. If so, we determine the parent of the tree. If the
* parent is one of the boxes which holds our various radio buttons, we
* go process the button, as appropriate. If it is over an object of
* ours, but not within a parent box, we just ignore the click.
*
*************************************************************************/
do_btn()
{
int mouse_x;
int mouse_y;
int selobject;
int dmy;
graf_mkstate(&mouse_x, &mouse_y, &dmy, &dmy);
selobject = objc_find(palttree, R_TREE, MAX_DEPTH, mouse_x, mouse_y);
if (selobject != -1) {
switch (obj_parent(palttree, selobject)) {
case PALTPCOL:
new_color(selobject, TRUE);
break;
case PALTPRED:
case PALTPGRN:
case PALTPBLU:
new_settings(selobject);
break;
} /* END switch (obj_parent(selobject)) */
} /* END if (selobject != -1) */
}
/**************************************************************************
*
* main routine
* Call the init routine, then fall into a do-forever evnt_multi() loop.
*
*************************************************************************/
main()
{
int dmy;
int event;
int msgbuf[8];
prg_init();
while (TRUE) {
event = evnt_multi(
MU_MESAG | MU_BUTTON,
1,1,1, /* mbclicks, mbmask, mbstate*/
0,0,0,0,0, /* Mouse event rectangle 1 */
0,0,0,0,0, /* Mouse event rectangle 2 */
msgbuf, /* Message buffer */
0,0, /* timer event, time = 0,0 */
&dmy, &dmy, /* Mouse x & y at event */
&dmy, /* Mouse button at event */
&dmy, /* Keystate at event */
&dmy, /* Keypress at event */
&dmy); /* Mouse click count */
wind_update(BEG_UPDATE);
if (event & MU_MESAG)
do_msg(msgbuf);
if (event & MU_BUTTON)
do_btn();
wind_update(END_UPDATE);
} /* END while (TRUE) */
}